package com.hcj.springcloud.socket;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.time.LocalDateTime;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * rpc 服务端
 */
public class RpcServer {
    // 定义一个线程池
    private static final ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
    // 定义一个服务池，存放注册上来的服务
    private static final ConcurrentHashMap<String, Class<?>> serviceRegister = new ConcurrentHashMap<>();

    /**
     * 注册实现类
     *
     * @param service
     * @param impl
     */
    public void register(Class<?> service, Class<?> impl) {
        serviceRegister.put(service.getSimpleName(), impl);
    }

    /**
     * 启动
     *
     * @param port
     */
    public void start(Integer port) {
        ServerSocket socket = null;
        try {
            socket = new ServerSocket();
            socket.bind(new InetSocketAddress("localhost", port));
            System.out.println("启动服务 = " + LocalDateTime.now());
            System.out.println("当前已注册的服务 = " + serviceRegister);

            while (true) {
                executor.execute(new Task(socket.accept()));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 任务
     */
    @Slf4j
    private static class Task implements Runnable {

        private Socket client = null;

        public Task(Socket client) {
            this.client = client;
        }

        @Override
        public void run() {
            ObjectInputStream input = null;
            ObjectOutputStream out = null;
            try {
                // 1. 获取 调用参数
                input = new ObjectInputStream(client.getInputStream());
                out = new ObjectOutputStream(client.getOutputStream());
                // 按约定的顺序 读取流内容
                String serviceName = input.readUTF();
                String methodName = input.readUTF();
                Class<?>[] parameterTypes = (Class<?>[]) input.readObject();
                Object[] arguments = (Object[]) input.readObject();
                log.info("服务端收到：serviceName:{}", serviceName);
                log.info("服务端收到：methodName:{}", methodName);
                log.info("服务端收到：parameterTypes:{}", parameterTypes);
                log.info("服务端收到：args:{}", arguments);
                Class serviceClass = serviceRegister.get(serviceName);
                if (serviceClass == null) {
                    throw new ClassNotFoundException(serviceName + "未找到！或者还未注册到服务");
                }
                // 1.1 调用方法
                Method method = serviceClass.getMethod(methodName, parameterTypes);
                Object result = method.invoke(serviceClass.newInstance(), arguments);
                System.out.println("服务端收计算的result = " + result);
                // 2. 输出结果
                out.writeObject(result);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    input.close();
                    out.close();
                    client.close();
                } catch (Exception e) {
                    System.out.println("资源释放异常" + LocalDateTime.now());
                }
            }
        }
    }
}
